import { isEmpty, strIsEmpty } from '@/utils/is.utils';

/**
 * 构建默认字典
 * @param dictList
 * @param defaultDict
 */
export function withBuildDefaultDict(dictList?: DictItem[], defaultDict: DictItem | DictItem[] = {
  label: '全部',
  value: ''
}): DictItem[] {
  defaultDict = Array.isArray(defaultDict) ? defaultDict : [defaultDict];
  return [...defaultDict, ...(dictList || [])];
}

/**
 * 根据 dict 的顺序调整 values 的顺序
 * @param values - 需要排序的值数组，例如 ['2', '1', '3'] 或 [2, 1, 3]
 * @param dict - 定义排序规则的字典数组，例如 [{label: '一', value: '1'}, {label: '二', value: '2'}, {label: '三', value: '3'}]
 - 排序后的值数组
 */
export function sortValuesByDict<T>(values: T[], dict: DictItem[]): T[] {
  // 创建一个排序映射，将 dict 的 value 转换为 string 类型作为键
  const dictMap: { [key: string]: number } = dict.reduce(
    (acc, dict, index) => {
      // 确保 dict 的 value 是 string 类型，用于作为键
      acc[String(dict.value)] = index;
      return acc;
    },
    {} as { [key: string]: number }
  );

  // 对原始数组进行排序
  return values.sort((a, b) => {
    // 将 values 的值转换为 string 类型，用于查找映射索引
    const valueA = String(a);
    const valueB = String(b);

    const indexA = dictMap[valueA];
    const indexB = dictMap[valueB];

    // 如果映射中找不到对应的值，则将其排在末尾
    return (
      (indexA !== undefined ? indexA : Number.MAX_SAFE_INTEGER)
      - (indexB !== undefined ? indexB : Number.MAX_SAFE_INTEGER)
    );
  });
}

/**
 * 对数据层级结构进行排序
 * @param data - 需要排序的层级数据
 排序后的层级数据
 */
export function sortGroupedData(data: DictItem[]): DictItem[] {
  /**
   * 汉字数字到阿拉伯数字的映射
   */
  const chineseToNumberMap: Record<string, number> = {
    一: 1,
    二: 2,
    三: 3,
    四: 4,
    五: 5,
    六: 6,
    七: 7,
    八: 8,
    九: 9
  };

  /**
   * 将汉字数字转换为阿拉伯数字
   * @param {string} chinese - 汉字数字
   {number} - 阿拉伯数字
   */
  function chineseToNumber(chinese: string): number {
    return chineseToNumberMap[chinese] ?? 0;
  }

  /**
   * 提取字符串的前缀和数字部分
   * @param {string} item - 要提取前缀的字符串
   {object} - 包含前缀和数字的对象
   */
  function extractPrefixAndNumber(item: string): {
    prefix: string
    number: number
  } {
    // 匹配前缀和数字部分，包括汉字数字和阿拉伯数字
    const match = item.match(
      /^([^一二三四五六七八九\d]+)([一二三四五六七八九\d]+)([^一二三四五六七八九\d]*)$/
    );
    if (match) {
      const prefix = match[1].trim();
      const numberStr = match[2];

      // 将汉字数字转换为阿拉伯数字
      const number = Number.isNaN(Number(numberStr))
        ? chineseToNumber(numberStr)
        : Number.parseInt(numberStr, 10);

      return { prefix, number };
    }
    return { prefix: item, number: 0 };
  }

  /**
   * 根据公用前缀分组
   * @param {DictItem[]} arr - 要分组的字符串数组
   {object} - 分组后的结果
   */
  interface GroupProps {
    [k: string]: { label: DictItem, number: number }[]
  }
  function groupByPrefix(arr: DictItem[]): GroupProps {
    const groups: GroupProps = {};

    arr.forEach(item => {
      const { prefix, number } = extractPrefixAndNumber(item.label);
      if (!groups[prefix]) {
        groups[prefix] = [];
      }
      groups[prefix].push({ label: item, number });
    });

    return groups;
  }

  /**
   * 对每个前缀的组按数字排序
   * @param {GroupProps} groups - 分组后的对象
   {DictItem[]} - 已排序的数组
   */
  function sortGroupedItems(groups: GroupProps): DictItem[] {
    return Object.keys(groups)
      .sort((a, b) => a.length - b.length) // 排序前缀
      .reduce((acc: DictItem[], prefix) => {
        const group = groups[prefix];
        return acc.concat(
          group
            .sort((a, b) => (a.number ?? 0) - (b.number ?? 0))
            .map(item => item.label)
        );
      }, []);
  }

  // 将数据分为数字和非数字两部分
  const numericItems = data.filter(item => !Number.isNaN(Number(item.label)));
  const nonNumericItems = data.filter(item => Number.isNaN(Number(item.label)));

  // 对非数字部分进行分组和排序
  const groupedNonNumericItems = groupByPrefix(nonNumericItems);
  const sortedNonNumericItems = sortGroupedItems(groupedNonNumericItems);

  // 对数字部分进行排序
  const sortedNumericItems = numericItems.sort(
    (a, b) => Number(a.label) - Number(b.label)
  );

  // 合并排序后的数字和非数字部分
  const sortedData = [...sortedNumericItems, ...sortedNonNumericItems];

  // 递归排序子级
  sortedData.forEach(item => {
    if (item.children && item.children.length > 0) {
      item.children = sortGroupedData(item.children);
    }
  });

  return sortedData;
}

/**
 * 格式化级联字典
 * @param values
 * @param dict
 */
export function formatCascadeDict(values: string[], dict: DictItem[]): string[] {
  const result: string[] = [];
  const treeItem = dict.find(item => item.value === values[0]);
  if (!treeItem) {
    return result;
  }
  result.push(treeItem.label);
  if (values.length > 1 && !isEmpty(treeItem.children)) {
    values = [...values].splice(1);
    result.push(...formatCascadeDict(values, treeItem.children));
  }
  return result;
}

/**
 * 字典值转换为文本
 * @param value 字典值
 * @param dict 字典选项
 */
export function dictVal2Text(value: string | number, dict: DictItem[]): string | number {
  if (strIsEmpty(value)) {
    return '';
  }
  const res = dict.find(item => {
    return item.value === value;
  });
  return res ? res.label || '' : value;
}

/**
 * 比较两个列表的通用方法
 *
 * @param {Array} listA - 第一个列表
 * @param {Array} listB - 第二个列表
 * @param {Array} options - 包含顺序的选项数组，数组中每个元素应具有 { value: '标识' } 结构
 * @param {string} key - 用于匹配 options 中的键
 {number} 返回比较结果，正数表示 listA 大于 listB，负数表示 listA 小于 listB，0 表示相等
 */
export function compareLists<K extends keyof DictItem, T = string | number>(
  listA: T[],
  listB: T[],
  options: DictItem[],
  key?: K
) {
  const getWeight = (list: T[] = []) => {
    return list.reduce((totalWeight, item) => {
      return (
        totalWeight
        + options?.findIndex(option => option[key || 'value'] === item)
      );
    }, 0);
  };

  const weightA = getWeight(listA);
  const weightB = getWeight(listB);

  return weightA - weightB;
}
